package com.zzz.java8;

import com.sun.org.apache.regexp.internal.RE;
import com.zzz.test.Attention;
import com.zzz.test.User;
import org.aspectj.weaver.ast.Var;
import org.junit.Test;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
 * @author zhuzhizun
 * @date 2021/8/11
 */
public class StreamTest {

    @Test
    public void sortTest() throws InterruptedException {
        User user1 = new User(6,"A",22);
        User user2 = new User(5,"B",19);
        User user3 = new User(3,"C",23);
        User user4 = new User(4,"D",22);

        ArrayList<User> arrayList = new ArrayList<>();
        arrayList.add(user1);
        arrayList.add(user2);
        arrayList.add(user3);
        arrayList.add(user4);

        arrayList.stream()
                .sorted(Comparator.comparing(User::getAge).thenComparingInt(User::getId))
                .forEach(System.out::println);

        arrayList.wait();

        Integer [] myArray = { 1, 2, 3 };
        List myList = Arrays.stream(myArray).collect(Collectors.toList());

        int [] myArray2 = { 1, 2, 3 };
        List<int[]> ints = Arrays.asList(myArray2);
        int[] array = (int[]) ints.get(0);
        System.out.println(array[0]);
//        List myList = Arrays.stream(myArray2).boxed().collect(Collectors.toList());

    }


    @Test
    public void streamTestOne() {
        String[] world = {"hello", "world"};
        Stream<String> stream = Arrays.stream(world);
        List<String> collect =
                stream.map(x -> x.split(""))
                        .flatMap(Arrays::stream)
                        .distinct()
                        .collect(Collectors.toList());
        collect.forEach(System.out::println);

    }

    @Test
    public void streamTestTwo() {

        int[] numbers = {3, 2, 5};
        int sum = Arrays.stream(numbers).reduce(0, Integer::sum);
        System.out.println(sum);


        int max = Arrays.stream(numbers).reduce(0, Integer::max);
        System.out.println(max);


    }

    @Test
    public void streamTestThree() {

        User user1 = new User(1, "zzz", 22);
        User user11 = new User(1, "zzz", 23);
        User user3 = new User(3, "zzz", 21);
        User user2 = new User(2, "yh", 26);
        User user33 = new User(3, "yh", 21);
        User user4 = new User(2, "yh", 15);
        List<User> userList = new ArrayList<>();
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);
        userList.add(user4);
        userList.add(user11);
        userList.add(user33);


        User user6 = new User(3, "yh", 21,new Attention(1,22));
        User user7 = new User(2, "yh", 15,new Attention(2,23));
        List<User> list = new ArrayList<>();
        list.add(user6);
        list.add(user7);
        Stream<Stream<Attention>> streamStream = list.stream()
                .map(user -> Stream.of(user).map(User::getAttention));
        // 第一个forEach  只是得到Stream<Attention>类型的流  在遍历里面的Attention
        streamStream.forEach(attentionStream -> attentionStream.forEach(System.out::println));

        // 直接遍历里面的Attention
        Stream<Attention> attentionStream = list.stream()
                .flatMap(user -> Stream.of(user).map(User::getAttention));
        attentionStream.forEach(System.out::println);



        int asInt = userList.stream()
                .mapToInt(u -> u.getAge())
                .max().getAsInt();
        System.out.println(asInt);

        IntSummaryStatistics collect1 = userList.stream().collect(Collectors.summarizingInt(User::getAge));
        System.out.println(collect1);

        String collect = userList.stream().map(User::getName).collect(Collectors.joining("--", "<-", "->"));
        System.out.println(collect);

        Map<String, Map<Integer, List<User>>> listMap = userList
                .stream()
                .collect(Collectors.groupingBy(User::getName, Collectors.groupingBy(User::getId)));
        listMap.forEach((k, v) -> {
            v.forEach((k1, v1) -> {
                System.out.println(k + ": " + k1 + " --" + v1);
            });
        });


    }

    @Test
    public void streamTestFour() {
        // 求和1-100
        IntStream intStream = IntStream.rangeClosed(0  , 100);
        int sum = intStream.sum();
        System.out.println(sum);


        Stream<int[]> stream = IntStream.rangeClosed(1, 100).boxed()
                .flatMap(a ->
                        IntStream.rangeClosed(a, 100)
                                .filter(b -> Math.sqrt(a * a + b * b) % 1 == 0)
                                .mapToObj(b -> new int[]{a, b, (int) Math.sqrt(a * a + b * b)})
                );
        stream.limit(5).forEach(x -> System.out.println(x[0] + "," + x[1] + "," + x[2]));

    }

    @Test
    public void streamTestFive() throws IOException, URISyntaxException {
        // 自定义字符串流
        Stream<String> stream = Stream.of("zzz", "yh");
        stream.map(String::toUpperCase).forEach(System.out::println);

        // 创建文件流
        Stream<String> lines = Files.lines(Paths.get(this.getClass().getClassLoader().getResource("data.txt").toURI()), Charset.defaultCharset());

        long count = lines.flatMap(line -> Arrays.stream(line.split(" ")))
                .distinct()
                .count();
        System.out.println(count);


    }

    @Test
    public void streamTestSix() {

        Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]})
                .limit(2)
                .forEach(t -> System.out.println("(" + t[0] + "," + t[1] + ")"));

        Stream.generate(Math::random).limit(5).forEach(System.out::println);
    }

    @Test
    public void streamTestSeven() throws Exception {
        User user = null;

        User zzz = Optional.ofNullable(user).orElse(new User(1, "zzz", 22));
        Optional.ofNullable(user).orElseThrow(RuntimeException::new);
        System.out.println(zzz);

    }

    @Test
    public void completableFutureTest() throws ExecutionException, InterruptedException, TimeoutException {
        User user = new User(1, "zzz", 22);
        Future<Integer> ageAsync = getAgeAsync(user);


        System.out.println("doSomethings.....");

        System.out.println(ageAsync.get(5,TimeUnit.SECONDS));

    }

    public Future<Integer> getAgeAsync(User user){

        return CompletableFuture.supplyAsync(() -> StreamTest.getAge(user));
      /*
        CompletableFuture<Integer> completableFuture = new CompletableFuture<>();
        new Thread(() -> {
            try {
                Integer age = getAge(user);
                completableFuture.complete(age);
            } catch (Exception e) {
                completableFuture.completeExceptionally(e);
            }

        }).start();

        return completableFuture;*/

    }

    public static Integer getAge(User user){
        try {
            TimeUnit.SECONDS.sleep(3);
//            throw new RuntimeException("睡过头了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return user.getAge();
    }

    public static long parallelSum(long n) {
        return Stream.iterate(1L, i -> i + 1)
                .limit(n)
                .parallel()
                .reduce(0L, Long::sum);
    }

    @Test
    public void localDateTest(){
        LocalDate localDate = LocalDate.of(2021, 8, 13);
        System.out.println(localDate.get(ChronoField.DAY_OF_YEAR));
        System.out.println(localDate.get(ChronoField.DAY_OF_MONTH));

        System.out.println(localDate.getDayOfWeek());
        System.out.println(LocalDate.now().getDayOfWeek());

        LocalDate localDate1 = LocalDate.of(2021, 8, 13);
        LocalDate date = localDate1.with(TemporalAdjusters.lastDayOfMonth());
        System.out.println(date);

        LocalDate with = localDate1.with(new NextWorkingDay());
        System.out.println(with);

    }



}
